﻿using SpotsHub.RouteService.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SpotsHub.RouteService.Strategy
{

    public class SimpleTraversalStrategy : StrategyBase
    {
        private const int maxWaypointCount = 10000;
        public override void Caculate()
        {
            foreach (var da in Plan.DriverAssignments)
            {
                PlanSingleDriver(da);
            }
        }

        public override int Priorty
        {
            get { return 20; }
        }

        private void PlanSingleDriver(DriverAssignment da)
        {
            if (da.UnresolvedWaypoints == null || da.UnresolvedWaypoints.Count() == 0)
            {
                return;
            }

            var wps = new List<Location>(da.UnresolvedWaypoints);

            var plannedLocs = new List<Location>();

            int rank = 0;
            Address s = Plan.WareHouse;

            while (wps.Count > 0)
            {
                var weights = GetWeights(s, wps.ToArray(), Plan.Method);
                if (weights != null)
                {
                    double m = weights.Keys.Min();
                    weights[m].Rank = rank++;
                    plannedLocs.Add(weights[m]);
                    wps.Remove(weights[m]);
                }
            }

            da.UnresolvedWaypoints = null;
            //da.GoWaypoints = plannedLocs.ToArray();
            Location[] pwps = plannedLocs.ToArray();
            List<Location> returnLocals = new List<Location>();
            foreach (var l in pwps)
            {
                if (l.Status == LocationStatus.ReadyForPickUp // Pickup location
                    && l.RelatedLocation != null 
                    && l.RelatedLocation.AssignedDriver == l.AssignedDriver // Same driver
                    && l.Rank > l.RelatedLocation.Rank) // Pickup is after delivery
                {
                    //TODO: Verify RelatedLocation status
                    plannedLocs.Remove(l.RelatedLocation);
                    returnLocals.Add(l.RelatedLocation);
                    l.RelatedLocation.Rank = maxWaypointCount;
                }
            }

            da.GoWaypoints = plannedLocs.OrderBy(l => l.Rank).ToArray();
            
            s = da.GoWaypoints.Last().Address;
            wps = new List<Location>(returnLocals);
            plannedLocs.Clear();
            rank = maxWaypointCount;
            while (wps.Count > 0)
            {
                var weights = GetWeights(s, wps.ToArray(), Plan.Method);
                if (weights != null)
                {
                    double m = weights.Keys.Min();
                    weights[m].Rank = rank++;
                    plannedLocs.Add(weights[m]);
                    wps.Remove(weights[m]);
                }
            }

            da.ReturningWaypoints = plannedLocs.OrderBy(l => l.Rank).ToArray();
        }

        private Dictionary<double, Location> GetWeights(Address start, Location[] ends, CaculateMethod method)
        {
            var res = new Dictionary<double, Location>();
            TravelInformation ti = _service.GetTravelInformation(start, ends.Select(l => l.Address));

            Dictionary<Address, double> r = null;
            switch (method)
            {
                case CaculateMethod.ByDistance:
                    r = ti.Distances;
                    break;
                case CaculateMethod.ByDuration:
                    r = ti.Durations;
                    break;
                default:
                    break;
            }

            foreach (var a in r.Keys)
            {
                double key = r[a];
                while (res.ContainsKey(key))
                {
                    key += 0.0001;
                }
                res.Add(key, ends.Where(l => l.Address == a).FirstOrDefault());
            }
            return res;
        }
    }
}